package autotd.server;

import java.net.*;

import java.util.*;
import java.awt.Point;
import java.io.*;

import autotd.*;

// Written by Ian Grunert
// Adapted from code written by Joseph Kuhen

// Appears to have some serious speed issues, centred around network operations.
// Can be used as a base point for thinking about more advanced building and shooting strategies

public class ObiruBot extends Thread {
	public ArrayList<String> towerMenu = new ArrayList<String>();
	
	public ArrayList<int[]> coordMenu = new ArrayList<int[]>();
	public GameMap theMap;

	public int cheapestTowerCost = 100;
	public int positionsExpanding; 

	public static String bestTower = "SuperSniper";
	
	SimulatorClient myCore;
	int menuPos;

	public ObiruBot(TDSimulator tdsim) throws Exception {
		myCore = new SimulatorClient(tdsim);
		menuPos = 0;
	}

	public void run() {
		// Start by determining the best coordinate to place the towers
		theMap = myCore.getMap();

		towerMenu.add("BasicWater");
		
		// Iterate over every point
		int currentTotal;
		int bestTotal = Integer.MIN_VALUE;

		for (int x = 0; x < theMap.getWidth(); x++) {
			for (int y = 0; y < theMap.getLength(); y++) {
				if (!theMap.isPath(new Point(x, y))) coordMenu.add(new int[] {x, y});
			}
		}

		Collections.sort(coordMenu, new pointCompare());
		/*
		for (int x = 0; x < theMap.getWidth(); x++) {
			for (int y = 0; y < theMap.getLength(); y++) {
				if (!theMap.isPath(new Point(x, y))) {
					currentTotal = 0;
					for (int px = x-1; px <= x+1; px++) {
						for (int py = y-1; py <= y+1; py++) {
							if (theMap.isValid(new Point(px, py)) && theMap.isPath(new Point(px,py))) {
								currentTotal++;
							}
						}
					}
					coordMenu.add(9-currentTotal, new int[] {x,y});
				}
			}
		}
		*/
		positionsExpanding = 2;

		System.out.println("Number of coordinates to choose from: " + coordMenu.size());

		System.out.println("Finished working out square values");

		long time;

		while (myCore.getPlayer().isAlive()) {
			time = System.currentTimeMillis();
			tryToBuy();
			System.out.println("Buy time: " + (System.currentTimeMillis() - time));
			time = System.currentTimeMillis();
			tryToShoot();
			System.out.println("Shoot time: " + (System.currentTimeMillis() - time));
			myCore.tick();
		}
		System.out.println("I died!");
	}

	boolean spacesFilled = false;
	
	public void tryToBuy() {
		if (spacesFilled) return;
		TowerType nextTower =  myCore.getTowerType(towerMenu.get(menuPos));
		int currentPos = 0;
		while (myCore.getPlayer().getMoney() >= cheapestTowerCost && currentPos <= positionsExpanding) {
			// If the current position already has 4 or more towers on it
			if (theMap.getTowerStack(new Point(coordMenu.get(currentPos)[0], coordMenu.get(currentPos)[1])).size() < 4) {
				// System.out.println("Trying to buy " + towerMenu[menuPos] + " at " + java.util.Arrays.toString(coordMenu.get(currentPos)));
				if ((myCore.getPlayer().getMoney() >= nextTower.Cost)) {
					myCore.placeTower(nextTower, coordMenu.get(currentPos)[0], coordMenu.get(currentPos)[1]);
				}
				// boolean result = myCore.placeTower(nextTower, coordMenu.get(currentPos)[0], coordMenu.get(currentPos)[1]);
				// System.out.println(result);
				menuPos = (menuPos + 1) % towerMenu.size();
				nextTower =  myCore.getTowerType(towerMenu.get(menuPos));
				if (menuPos==0) currentPos++;
			} else {
				// At height 4, so try and buy the best tower here
				// System.out.println("Trying to buy " + bestTower + " at " + java.util.Arrays.toString(coordMenu.get(currentPos)));
				boolean result = false;
				if ((myCore.getPlayer().getMoney() >= myCore.getTowerType(bestTower).Cost)) {
					result = myCore.placeTower(myCore.getTowerType(bestTower), coordMenu.get(currentPos)[0], coordMenu.get(currentPos)[1]);
				}				
				// boolean result = myCore.placeTower(myCore.getTowerType(bestTower), coordMenu.get(currentPos)[0], coordMenu.get(currentPos)[1]);
				// System.out.println(result);
				// And go to the next position
				if (result == true && currentPos == positionsExpanding) {
					positionsExpanding++;
					towerMenu.clear();
					towerMenu.add("SuperFast");
					cheapestTowerCost = 400;
					menuPos = (menuPos + 1) % towerMenu.size();
				}
				currentPos++;
				if (currentPos == coordMenu.size()){
					spacesFilled = true;
					return;
				}
			}
		}
	}

	public void tryToShoot() {
		ArrayList<Tower> towers = new ArrayList<Tower>(myCore.getPlacedTowers());
		ArrayList<Monster> monsters = new ArrayList<Monster>(myCore.getActiveMonsters());
		// Sort Monsters in ascending order of health
		Collections.sort(monsters, new monsterComparator());
		// And sort Towers in ascending order of power
		Collections.sort(towers, new towerComparator());
		boolean somethingHappened;
		do {
			somethingHappened = false;
			for (Tower t : towers) {
				if (!t.ready()) {
					continue;
				}
				for (Monster m : monsters) {
					if (m.isDead() || !GameMap.inRange(t.pos, m.pos, t.Type.Range)) {
						continue;
					}
					// System.out.println("Trying to shoot " + m + " with " + t);
					boolean result = myCore.shootMonster(t.pos, m);
					// System.out.println(result);
					somethingHappened = result || somethingHappened;
					if(result) break;
				}
			}
		} while (somethingHappened);
	}


	
	
	
	public static void main(String[] args) throws Exception {
		TDSimulator sim = TDSimulator.getDefaultSimulator();
		if (sim == null) {
			System.err.println("Unable to load server settings. Please check to ensure that the file actually exists and has the correct format!");
			System.exit(-1);
		}
		ObiruBot bot = new ObiruBot(sim);
		bot.start();
	}

	class pointCompare implements Comparator<int[]> {
		public int compare (int[] p1, int[] p2) {
			int totalP1 = 0;
			for (int px = p1[0]-1; px <= p1[0]+1; px++) {
				for (int py = p1[1]-1; py <= p1[1]+1; py++) {
					if (theMap.isValid(new Point(px, py)) && theMap.isPath(new Point(px,py))) {
						totalP1++;
					}
				}
			}

			int totalP2 = 0;
			for (int px = p2[0]-1; px <= p2[0]+1; px++) {
				for (int py = p2[1]-1; py <= p2[1]+1; py++) {
					if (theMap.isValid(new Point(px, py)) && theMap.isPath(new Point(px,py))) {
						totalP2++;
					}
				}
			}
			return totalP2 - totalP1;
		}
	}

	class monsterComparator implements Comparator<Monster> {
		public int compare (Monster m1, Monster m2) {
			return m1.health - m2.health;
		}
	}

	class towerComparator implements Comparator<Tower> {
		public int compare (Tower t1, Tower t2) {
			return t1.Type.Power - t2.Type.Power;
		}
	}
}
